package uk.co.nazz.f21mc_a2.diary;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;

import uk.co.nazz.f21mc_a2.ui.EventEditor;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Attendees;
import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events;
import android.util.Log;
import android.widget.Toast;

/**
 * @author Andrew The diary class creates a diary content provider database
 *         (Calendar) and contains methods to create/update.
 */
public class Diary {
	private Uri diaryUri;
	private Context context;

	private static final String ACCOUNT_NAME = "private";
	private static final String INT_NAME_PREFIX = "priv";
	private static final int CAL_COLOUR = 0xFF003B6F;
	private String internalName;

	public Diary(Context context, String diaryName) {
		this.context = context;
		diaryUri = getDiary(diaryName);

	}

	public Uri getDiaryUri() {
		return diaryUri;
	}

	public int getDiaryId() {
		return Integer.parseInt(diaryUri.getLastPathSegment());
	}

	// check to see if the calendar exists already
	// if so return its ID, if not create it.
	private Uri getDiary(String diaryName) {

		internalName = INT_NAME_PREFIX + diaryName;
		Uri uri = Uri.EMPTY;
		String[] projection = new String[] { Calendars.NAME, Calendars._ID };

		// Initialise string arrays for the selection clauses and selection
		// arguments to return a record for the calendar if it exists

		String mSelectionClause = Calendars.NAME + " = ?";
		String[] mSelectionArgs = { internalName };

		// query the database
		Log.i("F21MC_2", "Querying for existing calendar");
		Cursor cursor = context.getContentResolver().query(
				Calendars.CONTENT_URI, projection, mSelectionClause,
				mSelectionArgs, null);
		Log.i("F21MC_2", "Counting returned rows");

		// iterate through records to check to see if a match occurs
		if (cursor.moveToFirst()) {
			Log.i("F21MC_2", "Number of rows: " + cursor.getCount());
			do {
				Log.i("F21MC_2", "Checking calendar names");
				String existingDiaryName = cursor.getString(0);
				// test to see if the calendar is already registered
				Log.i("F21MC_2", "Checking calendar name: " + existingDiaryName);
				if (existingDiaryName.equals(internalName)) {
					// a match has been found, the diary has already been
					// created
					uri = ContentUris.withAppendedId(Calendars.CONTENT_URI,
							Integer.parseInt(cursor.getString(1)));
					break;
				}
			} while (cursor.moveToNext());
		}
		Log.i("F21MC_2", "Uri:" + uri.toString());
		if (uri.equals(Uri.EMPTY)) {
			// no matching diary found so create one
			uri = createDiary(diaryName);
		}
		return uri;
	}

	/**
	 * @param calName
	 *            - The name of the calendar
	 * @return URI of the calendar
	 */
	private Uri createDiary(String calName) {
		Log.i("F21MC_2", "Creating new calendar");
		// return the id of the newly created calendar
		return context.getContentResolver().insert(buildCalUri(),
				buildCalendarValues(calName));

	}

	/**
	 * 
	 * @param title
	 *            - title of the event
	 * @param start
	 *            - Calendar object for the start time and date
	 * @param end
	 *            - Calendar object for the end time and date
	 * @param description
	 *            - text description of the event
	 * @param recurrenceRule
	 *            - RRULE as defined by the iCalendar specification defined in
	 *            RFC5545
	 * @param attendees
	 *            - Array of attendee objects
	 * @param location
	 *            - text description of location
	 * @param activityContext
	 *            - context
	 * @return - the _ID of the event
	 * 
	 *         This method creates an event entry
	 */
	public long createEvent(String title, Calendar start, Calendar end,
			String description, String recurrenceRule,
			ArrayList<Attendee> attendees, String location,
			Context activityContext) {

		ContentResolver cr = context.getContentResolver();
		ContentValues values = buildEventValues(title, start, end, description,
				recurrenceRule, location);

		Uri uri = cr.insert(Events.CONTENT_URI, values);
		long eventId = Long.parseLong(uri.getLastPathSegment());
		Toast toast = Toast.makeText(context, "Event ID:" + eventId
				+ " created", Toast.LENGTH_SHORT);
		toast.show();

		addAttendees(attendees, eventId, activityContext);
		return eventId;
	}

	// add attendees to an event
	private void addAttendees(ArrayList<Attendee> attendees, Long eventId,
			Context activityContext) {

		ContentValues values = new ContentValues();
		ContentResolver cr = context.getContentResolver();

		if (attendees.size() > 0) {
			for (Attendee attendee : attendees) {

				values.clear();
				values.put(Attendees.EVENT_ID, eventId);
				values.put(Attendees.ATTENDEE_NAME, attendee.getName());
				values.put(Attendees.ATTENDEE_EMAIL, attendee.getEmail());
				values.put(Attendees.ATTENDEE_IDENTITY,
						Integer.toString(attendee.getId()));
				cr.insert(Attendees.CONTENT_URI, values);

			}
		}
	}

	/**
	 * 
	 @param title
	 *            - title of the event
	 * @param start
	 *            - Calendar object for the start time and date
	 * @param end
	 *            - Calendar object for the end time and date
	 * @param description
	 *            - text description of the event
	 * @param recurrenceRule
	 *            - RRULE as defined by the iCalendar specification defined in
	 *            RFC5545
	 * @param attendees
	 *            - Array of attendee objects
	 * @param location
	 *            - text description of location
	 * @param activityContext
	 *            - context
	 * @param eventId
	 *            - the _ID of the event to be updated
	 */
	public void updateEvent(String title, Calendar start, Calendar end,
			String description, String recurrenceRule,
			ArrayList<Attendee> attendees, String location, String eventId) {

		ContentResolver cr = context.getContentResolver();
		ContentValues values = buildEventValues(title, start, end, description,
				recurrenceRule, location);
		Uri eventItemUri = ContentUris.withAppendedId(Events.CONTENT_URI,
				Long.parseLong(eventId));
		int result = cr.update(eventItemUri, values, null, null);
		if (result > 0) {
			Toast toast = Toast.makeText(context, "Event ID: " + eventId
					+ " updated", Toast.LENGTH_SHORT);
			toast.show();

		} else {
			Toast toast = Toast.makeText(context, "Event ID: " + eventId
					+ " update failed", Toast.LENGTH_SHORT);
			toast.show();
		}

	}

	/**
	 * Deletes and event
	 * 
	 * @param eventId
	 *            - the _ID of the event to be deleted
	 * @return - true if event successfully deleted
	 */
	public Boolean deleteEvent(String eventId) {

		Uri calendarUri = Events.CONTENT_URI;
		Uri uri = ContentUris.withAppendedId(calendarUri,
				Long.parseLong(eventId));
		return context.getContentResolver().delete(uri, null, null) > 0;

	}

	// build content values for creating and updating events
	private ContentValues buildEventValues(String title, Calendar start,
			Calendar end, String description, String recurrenceRule,
			String location) {
		ContentValues values = new ContentValues();
		values.put(Events.DTSTART, start.getTimeInMillis());
		values.put(Events.DTEND, end.getTimeInMillis());
		values.put(Events.TITLE, title);
		values.put(Events.DESCRIPTION, description);
		values.put(Events.CALENDAR_ID, getDiaryId());
		values.put(Events.EVENT_TIMEZONE, TimeZone.getDefault()
				.getDisplayName());

		values.put(Events.EVENT_LOCATION, location);
		values.put(Events.ACCESS_LEVEL, Events.ACCESS_PUBLIC);
		// check for a selected recurrence rule
		if (!recurrenceRule.equals(EventEditor.RECURRENCE_NONE)) {
			values.put(Events.RRULE, recurrenceRule.trim());
		}
		values.put(Events.ALL_DAY, 0);
		return values;
	}

	// build content values for creating a new calendar
	private ContentValues buildCalendarValues(String calName) {
		ContentValues val = new ContentValues();
		val.put(Calendars.ACCOUNT_NAME, ACCOUNT_NAME);
		val.put(Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL);
		val.put(Calendars.NAME, internalName);
		val.put(Calendars.CALENDAR_DISPLAY_NAME, calName);
		val.put(Calendars.CALENDAR_COLOR, CAL_COLOUR);
		val.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER);
		val.put(Calendars.OWNER_ACCOUNT, ACCOUNT_NAME);
		val.put(Calendars.VISIBLE, 1);
		val.put(Calendars.SYNC_EVENTS, 1);
		return val;
	}

	// build URI for the creation of a new calendar
	private static Uri buildCalUri() {
		Uri.Builder builder = CalendarContract.Calendars.CONTENT_URI
				.buildUpon();
		builder.appendQueryParameter(Calendars.ACCOUNT_NAME, ACCOUNT_NAME);
		builder.appendQueryParameter(Calendars.ACCOUNT_TYPE,
				CalendarContract.ACCOUNT_TYPE_LOCAL);
		builder.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER,
				"true");
		return builder.build();
	}

	/**
	 * 
	 * @param eventId
	 *            - the _ID of the event to be queried
	 * @return - true if the event specified is recurring
	 */
	public Boolean getIsRecurring(String eventId) {
		// the events columns to retrieve
		Boolean isRecurring = false;
		String[] projection = new String[] { Events.RRULE };

		// This is the select criteria
		String selection = "(" + Events._ID + " =? )";

		String[] seletionArgs = new String[] { eventId };

		Cursor cursor = context.getContentResolver().query(Events.CONTENT_URI,
				projection, selection, seletionArgs, null);

		while (cursor.moveToFirst()) {
			isRecurring = cursor.getString(cursor.getColumnIndex(Events.RRULE))
					.length() > 0;

		}
		return isRecurring;
	}

}
